home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / game / wins1726.zip / CALMANFP.ASM < prev    next >
Assembly Source File  |  1992-01-10  |  43KB  |  1,124 lines

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ; calmanfp.asm - floating point version of the calcmand.asm file
  3. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4. ; The following code was adapted from a little program called "Mandelbrot
  5. ; Sets by Wesley Loewer" which had a very limited distribution (my
  6. ; Algebra II class).  It didn't have any of the fancy integer math, but it
  7. ; did run floating point stuff pretty fast.
  8. ;
  9. ; The code was originally optimized for a 287 ('cuz that's what I've got)
  10. ; and for a large maxit (ie: use of generous overhead outside the loop to get
  11. ; slightly faster code inside the loop), which is generally the case when
  12. ; Fractint chooses to use floating point math.  This code also has the
  13. ; advantage that once the initial parameters are loaded into the fpu
  14. ; register, no transfers of fp values to/from memory are needed except to
  15. ; check periodicity and to show orbits and the like.  Thus, values keep all
  16. ; the significant digits of the full 10 byte real number format internal to
  17. ; the fpu.  Intermediate results are not rounded to the normal IEEE 8 byte
  18. ; format (double) at any time.
  19. ;
  20. ; The non fpu specific stuff, such as periodicity checking and orbits,
  21. ; was adapted from CALCFRAC.C and CALCMAND.ASM.
  22. ;
  23. ; This file must be assembled with floating point emulation turned on.  I
  24. ; suppose there could be some compiler differences in the emulation
  25. ; libraries, but this code has been successfully tested with the MSQC 2.51
  26. ; and MSC 5.1 emulation libraries.
  27. ;
  28. ;                                               Wes Loewer
  29. ;
  30. ; and now for some REAL fractal calculations...
  31. ; (get it, real, floating point..., never mind)
  32. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  33.  
  34. ;                        required for compatibility if Turbo ASM
  35. IFDEF ??version
  36. MASM51
  37. QUIRKS
  38. ENDIF
  39.  
  40. .8086
  41. .8087
  42.  
  43. .MODEL medium,c
  44.  
  45. ; external functions
  46. EXTRN   keypressed:FAR          ; this routine is in 'general.asm'
  47. EXTRN   getakey:FAR             ; this routine is in 'general.asm'
  48. EXTRN   plot_orbit:FAR          ; this routine is in 'fracsubr.c'
  49. EXTRN   scrub_orbit:FAR         ; this routine is in 'fracsubr.c'
  50.  
  51. ; external data
  52. EXTRN init:WORD                 ; declared as type complex
  53. EXTRN parm:WORD                 ; declared as type complex
  54. EXTRN new:WORD                  ; declared as type complex
  55. EXTRN maxit:WORD
  56. EXTRN inside:WORD
  57. EXTRN outside:WORD
  58. EXTRN fpu:WORD                  ; fpu type: 87, 287, or 387
  59. EXTRN rqlim:QWORD               ; bailout (I never did figure out
  60.                 ;   what "rqlim" stands for. -Wes)
  61. EXTRN color:WORD
  62. EXTRN oldcolor:WORD
  63. EXTRN realcolor:WORD
  64. EXTRN periodicitycheck:WORD
  65. EXTRN reset_periodicity:WORD
  66. EXTRN closenuff:QWORD
  67. EXTRN fractype:WORD             ; Mandelbrot or Julia
  68. EXTRN kbdcount:WORD             ; keyboard counter
  69. EXTRN dotmode:WORD
  70. EXTRN show_orbit:WORD           ; "show-orbit" flag
  71. EXTRN orbit_ptr:WORD            ; "orbit pointer" flag
  72. EXTRN potflag:WORD              ; potential flag
  73. EXTRN magnitude:QWORD           ; when using potential
  74.  
  75. JULIAFP  EQU 6                  ; from FRACTYPE.H
  76. MANDELFP EQU 4
  77. GREEN    EQU 2                  ; near y-axis
  78. YELLOW   EQU 6                  ; near x-axis
  79.  
  80. initx    EQU <qword ptr init>   ; just to make life easier
  81. inity    EQU <qword ptr init+8>
  82. parmx    EQU <qword ptr parm>
  83. parmy    EQU <qword ptr parm+8>
  84. newx     EQU <qword ptr new>
  85. newy     EQU <qword ptr new+8>
  86.  
  87. ; Apparently, these might be needed for TC++ overlays. I don't know if
  88. ; these are really needed here since I am not familiar with TC++. -Wes
  89. FRAME   MACRO regs
  90.     push    bp
  91.     mov     bp, sp
  92.     IRP     reg, <regs>
  93.       push  reg
  94.       ENDM
  95.     ENDM
  96.  
  97. UNFRAME MACRO regs
  98.     IRP     reg, <regs>
  99.       pop reg
  100.       ENDM
  101.     pop bp
  102.     ENDM
  103.  
  104.  
  105. .DATA
  106.     align   2
  107. savedx                  DQ  ?
  108. savedy                  DQ  ?
  109. orbit_real              DQ  ?
  110. orbit_imag              DQ  ?
  111. close                   DD  0.01
  112. round_down_half         DD  0.5
  113. tmp_word                DW  ?
  114. inside_color            DW  ?
  115. periodicity_color       DW  ?
  116. ;savedand               DW  ?
  117. ;savedincr              DW  ?
  118. savedand                EQU     SI      ; this doesn't save much time or
  119. savedincr               EQU     DI      ; space, but it doesn't hurt either
  120.  
  121. .CODE
  122.  
  123. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  124. ; This routine is called once per image.
  125. ; Put things here that won't change from one pixel to the next.
  126. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  127. PUBLIC calcmandfpasmstart
  128. calcmandfpasmstart   PROC
  129.                     ; not sure if needed here
  130.     FRAME   <di,si>                 ; std frame, for TC++ overlays
  131.  
  132.     mov     ax,inside
  133.     cmp     ax,0                    ; if (inside color == maxiter)
  134.     jnl     non_neg_inside
  135.     mov     ax,maxit                ;   use maxit as inside_color
  136.  
  137. non_neg_inside:                         ; else
  138.     mov     inside_color,ax         ;   use inside as inside_color
  139.  
  140.     cmp     periodicitycheck,0      ; if periodicitycheck < 0
  141.     jnl     non_neg_periodicitycheck
  142.     mov     ax,7                    ;   use color 7 (default white)
  143. non_neg_periodicitycheck:               ; else
  144.     mov     periodicity_color,ax    ;   use inside_color still in ax
  145.     mov     oldcolor,0              ; no periodicity checking on 1st pixel
  146.     sub     ax,ax                   ; ax=0
  147.     UNFRAME <si,di>                 ; pop stack frame
  148.     ret
  149. calcmandfpasmstart       ENDP
  150.  
  151. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  152. ; floating point version of calcmandasm
  153. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  154. PUBLIC calcmandfpasm
  155. calcmandfpasm  PROC
  156.     FRAME   <di,si>                 ; std frame, for TC++ overlays
  157. ; initialization stuff
  158.     sub     ax,ax                   ; clear ax
  159.     cmp     periodicitycheck,ax     ; periodicity checking?
  160.     je      initoldcolor            ;  no, set oldcolor 0 to disable it
  161.     cmp     inside,-59              ; zmag?
  162.     je      initoldcolor            ;  set oldcolor to 0
  163.     cmp     reset_periodicity,ax    ; periodicity reset?
  164.     je      short initparms         ;  no, inherit oldcolor from prior invocation
  165.     mov     ax,maxit                ; yup.  reset oldcolor to maxit-250
  166.     sub     ax,250                  ; (avoids slowness at high maxits)
  167. initoldcolor:
  168.     mov     oldcolor,ax             ; reset oldcolor
  169.  
  170. initparms:
  171.     sub     ax,ax                   ; clear ax
  172.     mov     word ptr savedx,ax      ; savedx = 0.0
  173.     mov     word ptr savedx+2,ax    ; needed since savedx is a QWORD
  174.     mov     word ptr savedx+4,ax
  175.     mov     word ptr savedx+6,ax
  176.     mov     word ptr savedy,ax      ; savedy = 0.0
  177.     mov     word ptr savedy+2,ax    ; needed since savedy is a QWORD
  178.     mov     word ptr savedy+4,ax
  179.     mov     word ptr savedy+6,ax
  180.     inc     ax                      ; ax = 1
  181.     mov     savedand,ax             ; savedand = 1
  182.     mov     savedincr,ax            ; savedincr = 1
  183.     mov     orbit_ptr,0             ; clear orbits
  184.     dec     kbdcount                ; decrement the keyboard counter
  185.     jns     short nokey             ;  skip keyboard test if still positive
  186.     mov     kbdcount,10             ; stuff in a low kbd count
  187.     cmp     show_orbit,0            ; are we showing orbits?
  188.     jne     quickkbd                ;  yup.  leave it that way.
  189. ;this may need to be adjusted, I'm guessing at the "appropriate" values -Wes
  190.     mov     kbdcount,5000           ; else, stuff an appropriate count val
  191.     cmp     fpu,387                 ; ("appropriate" to the FPU)
  192.     je      short kbddiskadj        ;     ...
  193.     mov     kbdcount,3000           ;     ...
  194.     cmp     fpu,287                 ;     ...
  195.     je      short kbddiskadj        ;     ...
  196.     mov     kbdcount,1000           ;     ...
  197.     cmp     fpu,87                  ;     ...
  198.     je      short kbddiskadj        ;     ...
  199.     mov     kbdcount,500            ; emulation
  200. kbddiskadj:
  201.     cmp     dotmode,11              ; disk video?
  202.     jne     quickkbd                ;  no, leave as is
  203.     mov     cl,2                    ; yes, reduce count
  204.     shr     kbdcount,cl             ;  ...
  205.  
  206. quickkbd:
  207.     call    far ptr keypressed      ; has a key been pressed?
  208.     cmp     ax,0                    ;  ...
  209.     je      nokey                   ; nope.  proceed
  210.     mov     kbdcount,0              ; make sure it goes negative again
  211.     cmp     ax,'o'                  ; orbit toggle hit?
  212.     je      orbitkey                ;  yup.  show orbits
  213.     cmp     ax,'O'                  ; orbit toggle hit?
  214.     jne     keyhit                  ;  nope.  normal key.
  215. orbitkey:
  216.     call    far ptr getakey         ; read the key for real
  217.     mov     ax,1                    ; reset orbittoggle = 1 - orbittoggle
  218.     sub     ax,show_orbit           ;  ...
  219.     mov     show_orbit,ax           ;  ...
  220.     jmp     short nokey             ; pretend no key was hit
  221. keyhit:
  222.     mov     ax,-1                   ; return with -1
  223.     mov     color,ax                ; set color to -1
  224.     UNFRAME <si,di>                 ; pop stack frame
  225.     ret                             ; bail out!
  226. nokey:
  227.  
  228. ; OK, here's the heart of the floating point code.
  229. ; In my original program, the bailout value was loaded once per image and
  230. ; was left on the floating point stack after each pixel, and finally popped
  231. ; off the stack when the fractal was finished.  A lot of overhead for very
  232. ; little gain in my opinion, so I changed it so that it loads and unloads
  233. ; per pixel. -Wes
  234.  
  235.     fld     rqlim                   ; everything needs bailout first
  236.     mov     cx,maxit                ; using cx as loop counter
  237.     cmp     fpu,387                 ; jump to fpu specific code
  238.     je      start_387               ; 387, slight efficiency tweeking
  239.     cmp     fpu,87
  240.     je      to_start_87             ; too long to be a short jump
  241.     jmp     start_287               ; 287/emulation (original version)
  242. to_start_87:
  243.     jmp     start_87                ; 87, compatible with 8087 codes
  244.  
  245. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  246. ; _387 code is just like _287 code except that it uses an FADD instead
  247. ; of an FSCALE per orbit and also saves an FLD1 per pixel.
  248. ;
  249. ; You could use .386/.387 here, but it is not necessary.  The _387 floating
  250. ; point routines in this file do not have any 387 specific op-codes,
  251. ; only 387 specific optimizations.  (And plus my MS QuickAssembler does not
  252. ; recognize the .386/.387 directives.) -Wes
  253. ;
  254. .286
  255. .287
  256.  
  257. start_387:
  258.     cmp     fractype,JULIAFP        ; julia or mandelbrot set?
  259.     je      short dojulia_387       ; julia set - go there
  260.  
  261. ; Mandelbrot _387 initialization of stack
  262.     dec     cx                      ; always requires at least 1 iteration
  263.  
  264.                     ; the fpu stack is shown below
  265.                     ; st(0) ... st(7)
  266.                     ; b (already on stack)
  267.     fld     inity                   ; Cy b
  268.     fld     initx                   ; Cx Cy b
  269.     fld     st(1)                   ; Cy Cx Cy b
  270.     fadd    parmy                   ; Py+Cy Cx Cy b
  271.     fld     st                      ; Py+Cy Py+Cy Cx Cy b
  272.     fmul    st,st                   ; (Py+Cy)^2 Py+Cy Cx Cy b
  273.     fld     st(2)                   ; Cx (Py+Cy)^2 Py+Cy Cx Cy b
  274.     fadd    parmx                   ; Px+Cx (Py+Cy)^2 Py+Cy Cx Cy b
  275.     fmul    st(2),st                ; Px+Cx (Py+Cy)^2 (Py+Cy)(Px+Cx) Cx Cy b
  276.     fmul    st,st                   ; (Px+Cx)^2 (Py+Cy)^2 (Py+Cy)(Px+Cx) Cx Cy b
  277.     ; which is the next               x^2 y^2 xy Cx Cy b
  278.     jmp     short top_of_cx_loop_387 ; branch around the julia switch
  279.  
  280. dojulia_387:
  281.                     ; Julia 387 initialization of stack
  282.                     ; note that init and parm are "reversed"
  283.                     ; b (already on stack)
  284.     fld     parmy                   ; Cy b
  285.     fld     parmx                   ; Cx Cy b
  286.     fld     inity                   ; y Cx Cy b
  287.     fld     st                      ; y y Cx Cy b
  288.     fmul    st,st                   ; y^2 y Cx Cy b
  289.     fld     initx                   ; x y^2 y Cx Cy b
  290.     fmul    st(2),st                ; x y^2 xy Cx Cy b
  291.     fmul    st,st                   ; x^2 y^2 xy Cx Cy b
  292.  
  293. top_of_cx_loop_387:                     ; x^2 y^2 xy Cx Cy b
  294.     fsubr                           ; x^2-y^2 xy Cx Cy b
  295.     fadd    st,st(2)                ; x^2-y^2+Cx xy Cx Cy b
  296.     fxch                            ; xy x^2-y^2+Cx Cx Cy b
  297. ; FADD is faster than FSCALE for 387
  298.     fadd    st,st                   ; 2xy x^2-y^2+Cx Cx Cy b
  299.     fadd    st,st(3)                ; 2xy+Cy x^2-y^2+Cx Cx Cy b
  300.                     ; now same as the new
  301.                     ; y x Cx Cy b
  302.  
  303.     cmp     outside,-2              ; real, imag, mult, or sum ?
  304.     jg      no_save_new_xy_387      ; if not, then skip this
  305.     fld     st(1)                   ; x y x Cx Cy b
  306.     fstp    newx                    ; y x Cx Cy b
  307.     fst     newy                    ; y x Cx Cy b
  308. no_save_new_xy_387:
  309.  
  310.     cmp     inside,-100                     ; epsilon cross ?
  311.     jne     end_epsilon_cross_387
  312.     call    near ptr epsilon_cross          ; y x Cx Cy b
  313.     jcxz    pop_stack_387                   ; if cx=0, pop stack
  314. end_epsilon_cross_387:
  315.  
  316.     cmp     cx,oldcolor                     ; if cx >= oldcolor
  317.     jae     end_periodicity_check_387       ; don't check periodicity
  318.     call    near ptr periodicity_check_287_387  ; y x Cx Cy b
  319.     jcxz    pop_stack_387                   ; if cx=0, pop stack
  320. end_periodicity_check_387:
  321.  
  322.     cmp     show_orbit,0            ; is show_orbit clear
  323.     je      no_show_orbit_387       ; if so then skip
  324.     call    near ptr show_orbit_xy  ; y x Cx Cy b
  325. no_show_orbit_387:
  326.  
  327.                     ; y x Cx Cy b
  328.     fld     st(1)                   ; x y x Cx Cy b
  329.     fld     st(1)                   ; y x y x Cx Cy b
  330.     fmul    st(3),st                ; y x y xy Cx Cy b
  331.     fmulp   st(2),st                ; x y^2 xy Cx Cy b
  332.     fmul    st,st                   ; x^2 y^2 xy Cx Cy b
  333.     fld     st                      ; x^2 x^2 y^2 xy Cx Cy b
  334.     fadd    st,st(2)                ; x^2+y^2 x^2 y^2 xy Cx Cy b
  335.  
  336.     cmp     potflag,0               ; check for potential
  337.     je      no_potflag_387
  338.     fst     magnitude               ; if so, save magnitude
  339. no_potflag_387:
  340.  
  341.     fcomp   st(6)                   ; x^2 y^2 xy Cx Cy b
  342.     fstsw   ax
  343.     sahf
  344.     ja      over_bailout_387
  345.  
  346. ;less than or equal to bailout
  347.     loop    top_of_cx_loop_387      ; x^2 y^2 xy Cx Cy b
  348.  
  349. ; reached maxit, inside
  350.     mov     oldcolor,0FFFFh         ; check periodicity immediately next time
  351.     mov     ax,maxit
  352.     sub     kbdcount,ax             ; adjust the keyboard count
  353.     mov     realcolor,ax            ; save unadjusted realcolor
  354.     mov     ax,inside_color
  355.  
  356.     cmp     inside,-59              ; zmag ?
  357.     jne     no_zmag_387
  358.     fadd    st,st(1)                ; x^2+y^2 y^2 xy Cx Cy b
  359.     fimul   maxit                   ; maxit*|z^2| x^2 y^2 xy Cx Cy b
  360.  
  361. ; When type casting floating point variables to integers in C, the decimal
  362. ; is truncated.  When using FIST in asm, the value is rounded.  The following
  363. ; line cause the positive value to be truncated.
  364.     fsub    round_down_half
  365.  
  366.     fist    tmp_word                ; tmp_word = |z^2|*maxit
  367.     fwait
  368.     mov     ax,tmp_word
  369.     shr     ax,1                    ; |z^2|*maxit/2
  370.     inc     ax                      ; |z^2|*maxit/2+1
  371.  
  372. no_zmag_387:
  373.  
  374. pop_stack_387:
  375.     fninit
  376.  
  377.     mov     color,ax
  378.  
  379.     cmp     orbit_ptr,0             ; any orbits to clear?
  380.     je      calcmandfpasm_ret_387   ; nope.
  381.     call    far ptr scrub_orbit     ; clear out any old orbits
  382.     mov     ax,color                ; restore color
  383.                     ; speed not critical here in orbit land
  384.  
  385. calcmandfpasm_ret_387:
  386.     UNFRAME <si,di>                 ; pop stack frame
  387.     fwait                ; just to make sure
  388.     ret
  389.  
  390.     
  391. over_bailout_387:                       ; x^2 y^2 xy Cx Cy b
  392. ; outside
  393.     mov     ax,cx
  394.     sub     ax,10                   ; 10 more next time before checking
  395.     jns     no_fix_underflow_387
  396. ; if the number of iterations was within 10 of maxit, then subtracting
  397. ; 10 would underflow and cause periodicity checking to start right
  398. ; away.  Catching a period doesn't occur as often in the pixels at
  399. ; the edge of the set anyway.
  400.     sub     ax,ax                   ; don't check next time
  401. no_fix_underflow_387:
  402.     mov     oldcolor,ax             ; check when past this - 10 next time
  403.     mov     ax,maxit
  404.     sub     ax,cx                   ; leave 'times through loop' in ax
  405.  
  406. ; zero color fix
  407.     jnz     zero_color_fix_387
  408.     inc     ax                      ; if (ax == 0 ) ax = 1
  409. zero_color_fix_387:
  410.     mov     realcolor,ax            ; save unadjusted realcolor
  411.     sub     kbdcount,ax             ; adjust the keyboard count
  412.  
  413.     cmp     outside,-1              ; iter ? (most common case)
  414.     je      pop_stack_387
  415.     cmp     outside,-2        ; outside <= -2 ?
  416.     jle     special_outside_387     ; yes, go do special outside options
  417.     mov     ax,outside              ; use outside color
  418.     jmp     short pop_stack_387
  419. special_outside_387:
  420.     call    near ptr special_outside
  421.     jmp     short pop_stack_387
  422.  
  423. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  424. ; _287 version (closely resembles original code)
  425. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  426. .286
  427. .287
  428. ; let emulation fall through to the 287 code here
  429. ; as it seems to work slightly faster with this code
  430. start_287:      ; 287 and emulation
  431.     cmp     fractype,JULIAFP        ; julia or mandelbrot set?
  432.     je      short dojulia_287       ; julia set - go there
  433.  
  434. ; Mandelbrot _287 initialization of stack
  435.     dec     cx                      ; always requires at least 1 iteration
  436.  
  437.                     ; the fpu stack is shown below
  438.                     ; st(0) ... st(7)
  439.                     ; b (already on stack)
  440.     fld     inity                   ; Cy b
  441.     fld     initx                   ; Cx Cy b
  442.     fld     st(1)                   ; Cy Cx Cy b
  443.     fadd    parmy                   ; Py+Cy Cx Cy b
  444.     fld1                            ; 1 Py+Cy Cx Cy b
  445.     fld     st(1)                   ; Py+Cy 1 Py+Cy Cx Cy b
  446.     fmul    st,st                   ; (Py+Cy)^2 1 Py+Cy Cx Cy b
  447.     fld     st(3)                   ; Cx (Py+Cy)^2 1 Py+Cy Cx Cy b
  448.     fadd    parmx                   ; Px+Cx (Py+Cy)^2 1 Py+Cy Cx Cy b
  449.     fmul    st(3),st                ; Px+Cx (Py+Cy)^2 1 (Py+Cy)(Px+Cx) Cx Cy b
  450.     fmul    st,st                   ; (Px+Cx)^2 (Py+Cy)^2 1 (Py+Cy)(Px+Cx) Cx Cy b
  451.     ; which is the next                x^2 y^2 1 xy Cx Cy b
  452.     jmp     short top_of_cx_loop_287 ; branch around the julia switch
  453.  
  454. dojulia_287:
  455.                     ; Julia 287 initialization of stack
  456.                     ; note that init and parm are "reversed"
  457.                     ; b (already on stack)
  458.     fld     parmy                   ; Cy b
  459.     fld     parmx                   ; Cx Cy b
  460.     fld     inity                   ; y Cx Cy b
  461.     fld1                            ; 1 y Cx Cy b
  462.     fld     st(1)                   ; y 1 y Cx Cy b
  463.     fmul    st,st                   ; y^2 1 y Cx Cy b
  464.     fld     initx                   ; x y^2 1 y Cx Cy b
  465.     fmul    st(3),st                ; x y^2 1 xy Cx Cy b
  466.     fmul    st,st                   ; x^2 y^2 1 xy Cx Cy b
  467.  
  468. top_of_cx_loop_287:                     ; x^2 y^2 1 xy Cx Cy b
  469.     fsubr                           ; x^2-y^2 1 xy Cx Cy b
  470.     fadd    st,st(3)                ; x^2-y^2+Cx 1 xy Cx Cy b
  471.     fxch    st(2)                   ; xy 1 x^2-y^2+Cx Cx Cy b
  472. ; FSCALE is faster than FADD for 287
  473.     fscale                          ; 2xy 1 x^2-y^2+Cx Cx Cy b
  474.     fadd    st,st(4)                ; 2xy+Cy 1 x^2-y^2+Cx Cx Cy b
  475.                     ; now same as the new
  476.                     ; y 1 x Cx Cy b
  477.  
  478.     cmp     outside,-2              ; real, imag, mult, or sum ?
  479.     jg      no_save_new_xy_287      ; if not, then skip this
  480.     fld     st(2)                   ; x y 1 x Cx Cy b
  481.     fstp    newx                    ; y 1 x Cx Cy b
  482.     fst     newy                    ; y 1 x Cx Cy b
  483. no_save_new_xy_287:
  484.  
  485.     cmp     inside,-100                     ; epsilon cross ?
  486.     jne     end_epsilon_cross_287
  487.     call    near ptr epsilon_cross          ; y 1 x Cx Cy b
  488.     jcxz    pop_stack_6_287                 ; if cx=0, pop stack
  489. end_epsilon_cross_287:
  490.  
  491.     cmp     cx,oldcolor                     ; if cx >= oldcolor
  492.     jae     end_periodicity_check_287       ; don't check periodicity
  493.     call    near ptr periodicity_check_287_387 ; y 1 x Cx Cy b
  494.     jcxz    pop_stack_6_287                 ; if cx=0, pop stack
  495. end_periodicity_check_287:
  496.  
  497.     cmp     show_orbit,0            ; is show_orbit clear
  498.     je      no_show_orbit_287       ; if so then skip
  499.     call    near ptr show_orbit_xy  ; y 1 x Cx Cy b
  500. no_show_orbit_287:
  501.                     ; y 1 x Cx Cy b
  502.     fld     st(2)                   ; x y 1 x Cx Cy b
  503.     fld     st(1)                   ; y x y 1 x Cx Cy b
  504.     fmul    st(4),st                ; y x y 1 xy Cx Cy b
  505.     fmulp   st(2),st                ; x y^2 1 xy Cx Cy b
  506.     fmul    st,st                   ; x^2 y^2 1 xy Cx Cy b
  507.     fld     st                      ; x^2 x^2 y^2 1 xy Cx Cy b
  508.     fadd    st,st(2)                ; x^2+y^2 x^2 y^2 1 xy Cx Cy b
  509.  
  510.     cmp     potflag,0        ; check for potential
  511.     je      no_potflag_287
  512.     fst     magnitude        ; if so, save magnitude
  513. no_potflag_287:
  514.  
  515.     fcomp   st(7)                   ; x^2 y^2 1 xy Cx Cy b
  516.     fstsw   ax
  517.     sahf
  518.     ja      over_bailout_287
  519.  
  520. ;less than or equal to bailout
  521.     loop    top_of_cx_loop_287      ; x^2 y^2 1 xy Cx Cy b
  522.  
  523. ; reached maxit, inside
  524.     mov     oldcolor,0FFFFh         ; check periodicity immediately next time
  525.     mov     ax,maxit
  526.     sub     kbdcount,ax             ; adjust the keyboard count
  527.     mov     realcolor,ax            ; save unadjusted realcolor
  528.     mov     ax,inside_color
  529.  
  530.     cmp     inside,-59              ; zmag ?
  531.     jne     no_zmag_287
  532.     fadd    st,st(1)                ; x^2+y^2 y^2 1 xy Cx Cy b
  533.     fimul   maxit                   ; maxit*|z^2| x^2 y^2 1 xy Cx Cy b
  534.  
  535. ; When type casting floating point variables to integers in C, the decimal
  536. ; is truncated.  When using FIST in asm, the value is rounded.  The following
  537. ; line cause the positive value to be truncated.
  538.     fsub    round_down_half
  539.  
  540.     fist    tmp_word                ; tmp_word = |z^2|*maxit
  541.     fwait
  542.     mov     ax,tmp_word
  543.     shr     ax,1                    ; |z^2|*maxit/2
  544.     inc     ax                      ; |z^2|*maxit/2+1
  545.  
  546. no_zmag_287:
  547.  
  548. pop_stack_7_287:
  549. ; The idea here is just to clear the floating point stack.  There was a
  550. ; problem using FNINIT with the emulation library.  It didn't seem to
  551. ; properly clear the emulated stack, resulting in "stack overflow"
  552. ; messages.  Therefore, if emulation is being used, then FSTP's are used
  553. ; instead.
  554.  
  555.     cmp     fpu,0                   ; are we using emulation?
  556.     jne     no_emulation            ; if not, then jump
  557.     fstp    st
  558. ; you could just jump over this next check, but its faster to just check again
  559. pop_stack_6_287:
  560.     cmp     fpu,0                   ; are we using emulation?
  561.     jne     no_emulation            ; if not, then jump
  562.     fstp    st
  563.     fstp    st
  564.     fstp    st
  565.     fstp    st
  566.     fstp    st
  567.     fstp    st
  568.     jmp     short end_pop_stack_287
  569. no_emulation:                           ; if no emulation, then
  570.     fninit                          ;   use the faster FNINIT
  571. end_pop_stack_287:
  572.  
  573.     mov     color,ax
  574.  
  575.     cmp     orbit_ptr,0             ; any orbits to clear?
  576.     je      calcmandfpasm_ret_287   ; nope.
  577.     call    far ptr scrub_orbit     ; clear out any old orbits
  578.     mov     ax,color                ; restore color
  579.                     ; speed not critical here in orbit land
  580.  
  581. calcmandfpasm_ret_287:
  582.     UNFRAME <si,di>                 ; pop stack frame
  583.     fwait                           ; just to make sure
  584.     ret
  585.  
  586. over_bailout_287:                       ; x^2 y^2 1 xy Cx Cy b
  587. ; outside
  588.     mov     ax,cx
  589.     sub     ax,10                   ; 10 more next time before checking
  590.     jns     no_fix_underflow_287
  591. ; if the number of iterations was within 10 of maxit, then subtracting
  592. ; 10 would underflow and cause periodicity checking to start right
  593. ; away.  Catching a period doesn't occur as often in the pixels at
  594. ; the edge of the set anyway.
  595.     sub     ax,ax                   ; don't check next time
  596. no_fix_underflow_287:
  597.     mov     oldcolor,ax             ; check when past this - 10 next time
  598.     mov     ax,maxit
  599.     sub     ax,cx                   ; leave 'times through loop' in ax
  600.  
  601. ; zero color fix
  602.     jnz     zero_color_fix_287
  603.     inc     ax                      ; if (ax == 0 ) ax = 1
  604. zero_color_fix_287:
  605.     mov     realcolor,ax            ; save unadjusted realcolor
  606.     sub     kbdcount,ax             ; adjust the keyboard count
  607.  
  608.     cmp     outside,-1              ; iter ? (most common case)
  609.     je      pop_stack_7_287
  610.     cmp     outside,-2        ; outside <= -2 ?
  611.     jle     special_outside_287     ; yes, go do special outside options
  612.     mov     ax,outside              ; use outside color
  613.     jmp     short pop_stack_7_287
  614. special_outside_287:
  615.     call    near ptr special_outside
  616.     jmp     short pop_stack_7_287
  617.  
  618.  
  619. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  620. ; _87 code is just like 287 code except that it must use
  621. ;       fstsw   tmp_word
  622. ;       fwait
  623. ;       mov     ax,tmp_word
  624. ; instead of
  625. ;       fstsw   ax
  626. ;
  627. .8086
  628. .8087
  629. start_87:
  630.     cmp     fractype,JULIAFP        ; julia or mandelbrot set?
  631.     je      short dojulia_87        ; julia set - go there
  632.  
  633. ; Mandelbrot _87 initialization of stack
  634.     dec     cx                      ; always requires at least 1 iteration
  635.  
  636.                     ; the fpu stack is shown below
  637.                     ; st(0) ... st(7)
  638.                     ; b (already on stack)
  639.     fld     inity                   ; Cy b
  640.     fld     initx                   ; Cx Cy b
  641.     fld     st(1)                   ; Cy Cx Cy b
  642.     fadd    parmy                   ; Py+Cy Cx Cy b
  643.     fld1                            ; 1 Py+Cy Cx Cy b
  644.     fld     st(1)                   ; Py+Cy 1 Py+Cy Cx Cy b
  645.     fmul    st,st                   ; (Py+Cy)^2 1 Py+Cy Cx Cy b
  646.     fld     st(3)                   ; Cx (Py+Cy)^2 1 Py+Cy Cx Cy b
  647.     fadd    parmx                   ; Px+Cx (Py+Cy)^2 1 Py+Cy Cx Cy b
  648.     fmul    st(3),st                ; Px+Cx (Py+Cy)^2 1 (Py+Cy)(Px+Cx) Cx Cy b
  649.     fmul    st,st                   ; (Px+Cx)^2 (Py+Cy)^2 1 (Py+Cy)(Px+Cx) Cx Cy b
  650.     ; which is the next               x^2 y^2 1 xy Cx Cy b
  651.     jmp     short top_of_cx_loop_87 ; branch around the julia switch
  652.  
  653. dojulia_87:
  654.                     ; Julia 87 initialization of stack
  655.                     ; note that init and parm are "reversed"
  656.                     ; b (already on stack)
  657.     fld     parmy                   ; Cy b
  658.     fld     parmx                   ; Cx Cy b
  659.     fld     inity                   ; y Cx Cy b
  660.     fld1                            ; 1 y Cx Cy b
  661.     fld     st(1)                   ; y 1 y Cx Cy b
  662.     fmul    st,st                   ; y^2 1 y Cx Cy b
  663.     fld     initx                   ; x y^2 1 y Cx Cy b
  664.     fmul    st(3),st                ; x y^2 1 xy Cx Cy b
  665.     fmul    st,st                   ; x^2 y^2 1 xy Cx Cy b
  666.  
  667. top_of_cx_loop_87:                      ; x^2 y^2 1 xy Cx Cy b
  668.     fsubr                           ; x^2-y^2 1 xy Cx Cy b
  669.     fadd    st,st(3)                ; x^2-y^2+Cx 1 xy Cx Cy b
  670.     fxch    st(2)                   ; xy 1 x^2-y^2+Cx Cx Cy b
  671. ; FSCALE is faster than FADD for 87
  672.     fscale                          ; 2xy 1 x^2-y^2+Cx Cx Cy b
  673.     fadd    st,st(4)                ; 2xy+Cy 1 x^2-y^2+Cx Cx Cy b
  674.                     ; now same as the new
  675.                     ; y 1 x Cx Cy b
  676.  
  677.     cmp     outside,-2              ; real, imag, mult, or sum ?
  678.     jg      no_save_new_xy_87       ; if not, then skip this
  679.     fld     st(2)                   ; x y 1 x Cx Cy b
  680.     fstp    newx                    ; y 1 x Cx Cy b
  681.     fst     newy                    ; y 1 x Cx Cy b
  682. no_save_new_xy_87:
  683.  
  684.     cmp     inside,-100                     ; epsilon cross ?
  685.     jne     end_epsilon_cross_87
  686.     call    near ptr epsilon_cross          ; y 1 x Cx Cy b
  687.     jcxz    pop_stack_87                    ; if cx=0, pop stack
  688. end_epsilon_cross_87:
  689.  
  690.     cmp     cx,oldcolor                     ; if cx >= oldcolor
  691.     jae     no_periodicity_check_87         ; don't check periodicity
  692.     call    near ptr periodicity_check_87   ; y 1 x Cx Cy b
  693.     jcxz    pop_stack_87                    ; if cx=0, pop stack
  694. no_periodicity_check_87:
  695.  
  696.     cmp     show_orbit,0            ; is show_orbit clear
  697.     je      no_show_orbit_87        ; if so then skip
  698.     call    near ptr show_orbit_xy  ; y 1 x Cx Cy b
  699. no_show_orbit_87:
  700.  
  701.                     ; y 1 x Cx Cy b
  702.     fld     st(2)                   ; x y 1 x Cx Cy b
  703.     fld     st(1)                   ; y x y 1 x Cx Cy b
  704.     fmul    st(4),st                ; y x y 1 xy Cx Cy b
  705.     fmulp   st(2),st                ; x y^2 1 xy Cx Cy b
  706.     fmul    st,st                   ; x^2 y^2 1 xy Cx Cy b
  707.     fld     st                      ; x^2 x^2 y^2 1 xy Cx Cy b
  708.     fadd    st,st(2)                ; x^2+y^2 x^2 y^2 1 xy Cx Cy b
  709.  
  710.     cmp     potflag,0               ; check for potential
  711.     je      no_potflag_87
  712.     fst     magnitude               ; if so, save magnitude
  713. no_potflag_87:
  714.  
  715.     fcomp   st(7)                   ; x^2 y^2 1 xy Cx Cy b
  716.     fstsw   tmp_word
  717.     fwait
  718.     mov     ax,tmp_word
  719.     sahf
  720.     ja      over_bailout_87
  721.  
  722. ;less than or equal to bailout
  723.     loop    top_of_cx_loop_87       ; x^2 y^2 1 xy Cx Cy b
  724.  
  725. ; reached maxit
  726.     mov     oldcolor,0FFFFh         ; check periodicity immediately next time
  727.     mov     ax,maxit
  728.     sub     kbdcount,ax             ; adjust the keyboard count
  729.     mov     realcolor,ax            ; save unadjusted realcolor
  730.     mov     ax,inside_color
  731.  
  732.     cmp     inside,-59              ; zmag ?
  733.     jne     no_zmag_87
  734.     fadd    st,st(1)                ; x^2+y^2 y^2 1 xy Cx Cy b
  735.     fimul   maxit                   ; maxit*|z^2| x^2 y^2 1 xy Cx Cy b
  736.  
  737. ; When type casting floating point variables to integers in C, the decimal
  738. ; is truncated.  When using FIST in asm, the value is rounded.  The following
  739. ; line cause the positive value to be truncated.
  740.     fsub    round_down_half
  741.  
  742.     fist    tmp_word                ; tmp_word = |z^2|*maxit
  743.     fwait
  744.     mov     ax,tmp_word
  745.     shr     ax,1                    ; |z^2|*maxit/2
  746.     inc     ax                      ; |z^2|*maxit/2+1
  747.  
  748. no_zmag_87:
  749.  
  750. pop_stack_87:
  751.     fninit
  752.  
  753.     mov     color,ax
  754.  
  755.     cmp     orbit_ptr,0             ; any orbits to clear?
  756.     je      calcmandfpasm_ret_87    ; nope.
  757.     call    far ptr scrub_orbit     ; clear out any old orbits
  758.     mov     ax,color                ; restore color
  759.                     ; speed not critical here in orbit land
  760.  
  761. calcmandfpasm_ret_87:
  762.     UNFRAME <si,di>                 ; pop stack frame
  763.     fwait                ; just to make sure
  764.     ret
  765.  
  766. over_bailout_87:                        ; x^2 y^2 1 xy Cx Cy b
  767. ; outside
  768.     mov     ax,cx
  769.     sub     ax,10                   ; 10 more next time before checking
  770.     jns     no_fix_underflow_87
  771. ; if the number of iterations was within 10 of maxit, then subtracting
  772. ; 10 would underflow and cause periodicity checking to start right
  773. ; away.  Catching a period doesn't occur as often in the pixels at
  774. ; the edge of the set anyway.
  775.     sub     ax,ax                   ; don't check next time
  776. no_fix_underflow_87:
  777.     mov     oldcolor,ax             ; check when past this - 10 next time
  778.     mov     ax,maxit
  779.     sub     ax,cx                   ; leave 'times through loop' in ax
  780.  
  781. ; zero color fix
  782.     jnz     zero_color_fix_87
  783.     inc     ax                      ; if (ax == 0 ) ax = 1
  784. zero_color_fix_87:
  785.     mov     realcolor,ax            ; save unadjusted realcolor
  786.     sub     kbdcount,ax             ; adjust the keyboard count
  787.  
  788.     cmp     outside,-1              ; iter ? (most common case)
  789.     je      pop_stack_87
  790.     cmp     outside,-2        ; outside <= -2 ?
  791.     jle     special_outside_87      ; yes, go do special outside options
  792.     mov     ax,outside              ; use outside color
  793.     jmp     short pop_stack_87
  794. special_outside_87:
  795.     call    near ptr special_outside
  796.     jmp     short pop_stack_87
  797.  
  798. calcmandfpasm  ENDP
  799.  
  800. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  801. ; Since periodicity checking is used most of the time, I decided to
  802. ; separate the periodicity_check routines into a _287_387 version
  803. ; and an _87 version to achieve a slight increase in speed.  The
  804. ; epsilon_cross, show_orbit_xy, and special_outside routines are less
  805. ; frequently used and therefore have been implemented as single routines
  806. ; usable by the 8087 and up. -Wes
  807. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  808. .286
  809. .287
  810. periodicity_check_287_387   PROC    NEAR
  811. ; REMEMBER, the cx counter is counting BACKWARDS from maxit to 0
  812.                     ; fpu stack is either
  813.                     ; y x Cx Cy b (387)
  814.                     ; y 1 x Cx Cy b (287/emul)
  815.     cmp     fpu,387
  816.     jb      pc_load_x
  817.     fld     st(1)                   ; if 387
  818.     jmp     short pc_end_load_x
  819. pc_load_x:
  820.     fld     st(2)                   ; if 287/emul
  821. pc_end_load_x:
  822.                     ; x y ...
  823.     test    cx,savedand             ; save on 0, check on anything else
  824.     jnz     do_check_287_387        ;  time to save a new "old" value
  825.  
  826. ; save last value                       ; fpu stack is
  827.     fstp    savedx                  ; x y ...
  828.     fst     savedy                  ; y ...
  829.     dec     savedincr               ; time to lengthen the periodicity?
  830.     jnz     per_check_287_387_ret   ; if not 0, then skip
  831.     shl     savedand,1              ; savedand = (savedand << 1) + 1
  832.     inc     savedand                ; for longer periodicity
  833.     mov     savedincr,4             ; and restart counter
  834.     ret                             ; y ...
  835.  
  836. do_check_287_387:                       ; fpu stack is
  837.                     ; x y ...
  838.     fsub    savedx                  ; x-savedx y ...
  839.     fabs                            ; |x-savedx| y ...
  840.     fcomp   closenuff               ; y ...
  841.     fstsw   ax
  842.     sahf
  843.     ja      per_check_287_387_ret
  844.     fld     st                      ; y y ...
  845.     fsub    savedy                  ; y-savedy y ...
  846.     fabs                            ; |y-savedy| y ...
  847.     fcomp   closenuff               ; y ...
  848.     fstsw   ax
  849.     sahf
  850.     ja      per_check_287_387_ret
  851.                     ; caught a cycle!!!
  852.     mov     oldcolor,0FFFFh         ; check periodicity immediately next time
  853.  
  854.     mov     ax,maxit
  855.     mov     realcolor,ax            ; save unadjusted realcolor as maxit
  856.     sub     ax,cx                   ; subtract half c
  857.     sub     kbdcount,ax             ; adjust the keyboard count
  858.     mov     ax,periodicity_color    ; set color
  859.     sub     cx,cx                   ; flag to exit cx loop immediately
  860.  
  861. per_check_287_387_ret:
  862.     ret
  863. periodicity_check_287_387   ENDP
  864.  
  865. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  866. .8086
  867. .8087
  868. periodicity_check_87    PROC    NEAR
  869. ; just like periodicity_check_287_387 except for the use of
  870. ;       fstsw tmp_word
  871. ; instead of
  872. ;       fstsw ax
  873.  
  874. ; REMEMBER, the cx counter is counting BACKWARDS from maxit to 0
  875.     fld     st(2)                   ; x y ...
  876.     test    cx,savedand             ; save on 0, check on anything else
  877.     jnz     do_check_87             ;  time to save a new "old" value
  878.  
  879. ; save last value                       ; fpu stack is
  880.                     ; x y ...
  881.     fstp    savedx                  ; y ...
  882.     fst     savedy                  ; y ...
  883.     dec     savedincr               ; time to lengthen the periodicity?
  884.     jnz     per_check_87_ret        ; if not 0, then skip
  885.     shl     savedand,1              ; savedand = (savedand << 1) + 1
  886.     inc     savedand                ; for longer periodicity
  887.     mov     savedincr,4             ; and restart counter
  888.     ret                             ; y ...
  889.  
  890. do_check_87:                            ; fpu stack is
  891.                     ; x y ...
  892.     fsub    savedx                  ; x-savedx y ...
  893.     fabs                            ; |x-savedx| y ...
  894.     fcomp   closenuff               ; y ...
  895.     fstsw   tmp_word
  896.     fwait
  897.     mov     ax,tmp_word
  898.     sahf
  899.     ja      per_check_87_ret
  900.     fld     st                      ; y y ...
  901.     fsub    savedy                  ; y-savedy y ...
  902.     fabs                            ; |y-savedy| y ...
  903.     fcomp   closenuff               ; y ...
  904.     fstsw   tmp_word
  905.     fwait
  906.     mov     ax,tmp_word
  907.     sahf
  908.     ja      per_check_87_ret
  909.                     ; caught a cycle!!!
  910.     mov     oldcolor,0FFFFh         ; check periodicity immediately next time
  911.  
  912.     mov     ax,maxit
  913.     mov     realcolor,ax            ; save unadjusted realcolor as maxit
  914.     sub     ax,cx
  915.     sub     kbdcount,ax             ; adjust the keyboard count
  916.  
  917.     mov     ax,periodicity_color    ; set color
  918.     sub     cx,cx                   ; flag to exit cx loop immediately
  919.  
  920. per_check_87_ret:
  921.     ret
  922. periodicity_check_87       ENDP
  923.  
  924. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  925. .8086
  926. .8087
  927. epsilon_cross   PROC    NEAR
  928.                     ; fpu stack is either
  929.                     ; y x Cx Cy b (387)
  930.                     ; y 1 x Cx Cy b (287/87/emul)
  931.     cmp     fpu,387
  932.     jb      ec_load_x
  933.     fld     st(1)                   ; if 387
  934.     jmp     short ec_end_load_x
  935. ec_load_x:
  936.     fld     st(2)                   ; if 287/87/emul
  937. ec_end_load_x:                          ; x y ...
  938.  
  939.     fabs                            ; |x| y 1 x Cx Cy b
  940.     fcomp   close                   ; y 1 x Cx Cy b
  941.     fstsw   tmp_word
  942.     fwait
  943.     mov     ax,tmp_word
  944.     sahf
  945.     jae     no_x_epsilon_cross
  946.     mov     ax,maxit                ; x is close to y axis
  947.     sub     ax,cx                   ; leave 'times through loop' in ax
  948. ; zero color fix
  949.     jnz     zero_color_fix_1
  950.     inc     ax                      ; if (ax == 0 ) ax = 1
  951. zero_color_fix_1:
  952.     mov     realcolor,ax            ; save unadjusted realcolor
  953.     sub     kbdcount,ax             ; adjust the keyboard count
  954.     mov     ax,GREEN                ;
  955.     sub     cx,cx                   ; flag to end loop
  956.     mov     oldcolor,cx             ; don't check next time
  957.     ret                             ; return
  958. no_x_epsilon_cross:                     ; y 1 x Cx Cy b
  959.     fld     st                      ; y y 1 x Cx Cy b
  960.     fabs                            ; |y| y 1 x Cx Cy b
  961.     fcomp   close                   ; y 1 x Cx Cy b
  962.     fstsw   tmp_word
  963.     fwait
  964.     mov     ax,tmp_word
  965.     sahf
  966.     jae     no_y_epsilon_cross
  967.     mov     ax,maxit                ; y is close to x axis
  968.     sub     ax,cx                   ; leave 'times through loop' in ax
  969. ; zero color fix
  970.     jnz     zero_color_fix_2
  971.     inc     ax                      ; if (ax == 0 ) ax = 1
  972. zero_color_fix_2:
  973.     mov     realcolor,ax            ; save unadjusted realcolor
  974.     sub     kbdcount,ax             ; adjust the keyboard count
  975.     mov     ax,YELLOW
  976.     sub     cx,cx                   ; flag to end loop
  977.     mov     oldcolor,cx             ; don't check next time
  978.     ret                             ; return
  979. no_y_epsilon_cross:
  980.     ret
  981. epsilon_cross   ENDP
  982. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  983. .8086
  984. .8087
  985. show_orbit_xy   PROC NEAR USES cx si di
  986.     local    tmp_ten_byte_0:tbyte    ; stupid klooge for MASM 5.1 LOCAL bug
  987.     local    tmp_ten_byte_1:tbyte
  988.     local    tmp_ten_byte_2:tbyte
  989.     local    tmp_ten_byte_3:tbyte
  990.     local    tmp_ten_byte_4:tbyte
  991.     local    tmp_ten_byte_5:tbyte
  992.     local    tmp_ten_byte_6:tbyte
  993. ; USES is needed because in all likelyhood, plot_orbit surely
  994. ; uses these registers.  It's ok to have to push/pop's here in the
  995. ; orbits as speed is not crucial when showing orbits.
  996.  
  997.                     ; fpu stack is either
  998.                     ; y x Cx Cy b (387)
  999.                     ; y 1 x Cx Cy b (287/87/emul)
  1000.     cmp     fpu,387
  1001.     jb      so_load_x
  1002.     fld     st(1)                   ; if 387
  1003.     jmp     short so_end_load_x
  1004. so_load_x:
  1005.     fld     st(2)                   ; if 287/87/emul
  1006. so_end_load_x:
  1007.                     ; x y ...
  1008.                     ; and needs to returned as
  1009.                     ; y ...
  1010.  
  1011.     fstp    orbit_real              ; y ...
  1012.     fst     orbit_imag              ; y ...
  1013.     mov     ax,-1                   ; color for plot orbit
  1014.     push    ax                      ;       ...
  1015.     fwait
  1016.     push    word ptr orbit_imag+6   ; co-ordinates for plot orbit
  1017.     push    word ptr orbit_imag+4   ;       ...
  1018.     push    word ptr orbit_imag+2   ;       ...
  1019.     push    word ptr orbit_imag     ;       ...
  1020.     push    word ptr orbit_real+6   ; co-ordinates for plot orbit
  1021.     push    word ptr orbit_real+4   ;       ...
  1022.     push    word ptr orbit_real+2   ;       ...
  1023.     push    word ptr orbit_real     ;       ...
  1024.  
  1025. ; This next step could be C compiler dependant as plot_orbit must preserve
  1026. ; the top 6 levels of the fpu stack, which might be a lot to ask.
  1027. ; If it doesn't work, then just fstp the stack into ten byte
  1028. ; temporary variables and fld it back after returning.
  1029. ; It works as is with MS QuickC/QuickAssembler 2.51 without popping
  1030. ; the stack, so apparantly it's ok. whew!  -Wes
  1031.         fstp    tmp_ten_byte_1          ; store the stack in 80 bit form
  1032.         fstp    tmp_ten_byte_2
  1033.         fstp    tmp_ten_byte_3
  1034.         fstp    tmp_ten_byte_4
  1035.         fstp    tmp_ten_byte_5
  1036.         cmp     fpu,287                 ; with 287/87/emul the stack is 6 high
  1037.         jg      no_store_6              ; with 387+ it is only 5 high
  1038.         fstp    tmp_ten_byte_6
  1039. no_store_6:
  1040.         call    far ptr plot_orbit      ; display the orbit
  1041.         cmp     fpu,287
  1042.         jg      no_load_6
  1043.         fld     tmp_ten_byte_6          ; load them back in reverse order
  1044. no_load_6:
  1045.     fld    tmp_ten_byte_5
  1046.     fld    tmp_ten_byte_4
  1047.     fld    tmp_ten_byte_3
  1048.     fld    tmp_ten_byte_2
  1049.     fld    tmp_ten_byte_1
  1050.     add     sp,9*2                  ; clear out the parameters
  1051.     ret
  1052. show_orbit_xy   ENDP
  1053. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1054. .8086
  1055. .8087
  1056. special_outside PROC NEAR
  1057. ; When type casting floating point variables to integers in C, the decimal
  1058. ; is truncated.  When using FIST in asm, the value is rounded.  Using
  1059. ; "FSUB round_down_half" causes the values to be rounded down.
  1060.  
  1061.     cmp     outside,-2
  1062.     jne     not_real_287
  1063.     fld     newx
  1064.     fsub    round_down_half
  1065.     fistp   tmp_word
  1066.     add     ax,7
  1067.     fwait
  1068.     add     ax,tmp_word
  1069.     jmp     short check_color
  1070. not_real_287:
  1071.     cmp     outside,-3
  1072.     jne     not_imag_287
  1073.     fld     newy
  1074.     fsub    round_down_half
  1075.     fistp   tmp_word
  1076.     add     ax,7
  1077.     fwait
  1078.     add     ax,tmp_word
  1079.     jmp     short check_color
  1080. not_imag_287:
  1081.     cmp     outside,-4
  1082.     jne     not_mult_287
  1083.     fld     newy
  1084.     ftst                    ; check to see if newy == 0
  1085.     fstsw   tmp_word
  1086.     push    ax              ; save current ax value
  1087.     fwait
  1088.     mov     ax,tmp_word
  1089.     sahf
  1090.     pop     ax              ; retrieve ax (does not affect flags)
  1091.     jne     non_zero_y
  1092.     ret                     ; if y==0, return with normal ax
  1093. non_zero_y:
  1094.     fdivr   newx            ; newx/newy
  1095.     mov     tmp_word,ax
  1096.     fimul   tmp_word        ; ax*newx/newy  (Use FIMUL instead of MUL
  1097.     fsub    round_down_half ; to make it match the C code.)
  1098.     fistp   tmp_word
  1099.     fwait
  1100.     mov     ax,tmp_word
  1101.     jmp     short check_color
  1102. not_mult_287:
  1103.     cmp     outside,-5      ; currently always equal, but put here
  1104.     jne     not_sum_287     ; for future outside types
  1105.     fld     newx
  1106.     fadd    newy            ; newx+newy
  1107.     fsub    round_down_half
  1108.     fistp   tmp_word
  1109.     fwait
  1110.     add     ax,tmp_word
  1111.  
  1112. not_sum_287:
  1113. check_color:
  1114.     cmp     ax,maxit                ; use UNSIGNED comparison
  1115.     jbe     special_outside_ret     ; color < 0 || color > maxit
  1116.     sub     ax,ax                   ; ax = 0
  1117. special_outside_ret:
  1118.     ret
  1119. special_outside ENDP
  1120.  
  1121. .8086   ;just to be sure
  1122. .8087
  1123. END
  1124.